home *** CD-ROM | disk | FTP | other *** search
/ Clickx 115 / Clickx 115.iso / software / tools / windows / tails-i386-0.16.iso / live / filesystem.squashfs / usr / lib / perl5 / Glib / GenPod.pm < prev    next >
Encoding:
Perl POD Document  |  2012-02-20  |  39.7 KB  |  1,580 lines

  1. #
  2. #
  3. #
  4. # TODO:
  5. #    should we look at signals etc. for enums/flags?
  6. #    we're getting warnings about unregistered types with new enums/flags 
  7. #    stuff, quell them.
  8. #
  9.  
  10. package Glib::GenPod;
  11.  
  12. our $VERSION = '0.03';
  13.  
  14. use strict;
  15. use warnings;
  16. use Carp;
  17. use File::Spec;
  18. use Data::Dumper;
  19. use POSIX qw(strftime);
  20.  
  21. use Glib;
  22.  
  23. use base 'Exporter';
  24.  
  25. our @EXPORT = qw(
  26.     add_types
  27.     xsdoc2pod
  28.     podify_properties
  29.     podify_child_properties
  30.     podify_style_properties
  31.     podify_values
  32.     podify_signals
  33.     podify_ancestors
  34.     podify_interfaces
  35.     podify_methods
  36.     podify_enums_and_flags
  37.     podify_deprecated_by
  38. );
  39.  
  40. our $COPYRIGHT = undef;
  41. our $AUTHORS = 'Gtk2-Perl Team';
  42. our $MAIN_MOD = undef;
  43. our $YEAR = strftime "%Y", gmtime;
  44.  
  45. our ($xspods, $data);
  46.     
  47. =head1 NAME
  48.  
  49. Glib::GenPod - POD generation utilities for Glib-based modules
  50.  
  51. =head1 SYNOPSIS
  52.  
  53.  use Glib::GenPod;
  54.  
  55.  # use the defaults:
  56.  xsdoc2pod ($xsdocparse_output_file, $destination_dir);
  57.  
  58.  # or take matters into your own hands
  59.  require $xsdocparse_output_file;
  60.  foreach my $package (sort keys %$data) {
  61.      print "=head1 NAME\n\n$package\n\n";
  62.      print "=head1 METHODS\n\n" . podify_methods ($package) . "\n\n";
  63.  }
  64.  
  65. =head1 DESCRIPTION 
  66.  
  67. This module includes several utilities for creating pod for xs-based Perl
  68. modules which build on the Glib module's foundations.  The most important bits
  69. are the logic to convert the data structures created by xsdocparse.pl to
  70. describe xsubs and pods into method docs, with call signatures and argument
  71. descriptions, and converting C type names into Perl type names.  The rest of
  72. the module is mostly boiler-plate code to format and pretty-print information
  73. that may be queried from the Glib type system.
  74.  
  75. To make life easy for module maintainers, we also include a do-it-all function,
  76. xsdoc2pod(), which does pretty much everything for you.  All of the pieces it
  77. uses are publically usable, so you can do whatever you like if you don't like
  78. the default output.
  79.  
  80. =head1 DOCUMENTING THE XS FILES
  81.  
  82. All of the information used as input to the methods included here comes from
  83. the XS files of your project, and is extracted by Glib::ParseXSDoc's
  84. C<xsdocparse>.  This function creates an file containing Perl code that may be
  85. eval'd or require'd to recreate the parsed data structures, which are a list of
  86. pods from the verbatim C portion of the XS file (the xs api docs), and a hash
  87. of the remaining data, keyed by package name, and including the pods and xsubs
  88. read from the rest of each XS file following the first MODULE line.
  89.  
  90. Several custom POD directives are recognized in the XSubs section.  Note that
  91. each one is sought as a paragraph starter, and must follow a C<=cut> directive.
  92.  
  93. =over
  94.  
  95. =item =for object Package::Name
  96.  
  97. All xsubs and pod from here until the next object directive or MODULE line
  98. will be placed under the key 'I<Package::Name>' in xsdocparse's data
  99. structure.  Everything from this line to the next C<=cut> is included as a
  100. description POD.
  101.  
  102. =item =for object Package::Name (Other::Package::Name)
  103.  
  104. Generate POD in I<Package::Name> but for the package I<Other::Package::Name>.
  105. This is useful if you want POD to appear in a different namespace but still
  106. want the automatically generated hierarchy, signal and property listing,
  107. etc. from the original namespace.  For example:
  108.  
  109.   =for object Gnome2::PanelApplet::main (Gnome2::PanelApplet)
  110.   =cut
  111.  
  112. This will create Gnome2/PanelApplet/main.pod containing the automatically
  113. generated documentation for Gnome2::PanelApplet (hierarchy, signals, etc.) plus
  114. the method listing from the current XS file.
  115.  
  116. =item =for enum Package::Name
  117.  
  118. =item =for flags Package::Name
  119.  
  120. This causes xsdoc2pod to call C<podify_values> on I<Package::Name> when
  121. writing the pod for the current package (as set by an object directive or
  122. MODULE line).  Any text in this paragraph, to the next C<=cut>, is included
  123. in that section.
  124.  
  125. =item =for deprecated_by Package::Name
  126.  
  127. Used to add a deprecation warning, indicating I<Package::Name> as an
  128. alternative way to achieve the same functionality.  There may be any number
  129. these in each package.
  130.  
  131. =item =for see_also L<some_thing_to_see>
  132.  
  133. Used to add extra see alsos onto the end of the parents, if any, for a given
  134. object.  Anything following the space behind see_also up to the end of the
  135. line will be placed onto the list of "see also"s.  There may be any number of
  136. these in each package.
  137.  
  138. =item =for apidoc
  139.  
  140. =item =for apidoc Full::Symbol::name
  141.  
  142. Paragraphs of this type document xsubs, and are associated with the xsubs
  143. by xsdocparse.pl.  If the full symbol name is not included, the paragraph
  144. must be attached to the xsub declaration (no blank lines between C<=cut> and
  145. the xsub).
  146.  
  147. Within the apidoc PODs, we recognize a few special directives (the "for\s+"
  148. is optional on these):
  149.  
  150. =over
  151.  
  152. =item =for signature ...
  153.  
  154. Override the generated call signature with the ... text.  If you include
  155. multiple signature directives, they will all be used.  This is handy when
  156. you want to change the return type or list different ways to invoke an
  157. overloaded method, like this:
  158.  
  159.  =for apidoc
  160.  
  161.  =signature bool Class->foo
  162.  
  163.  =signature ($thing, @other) = $object->foo ($it, $something)
  164.  
  165.  Text in here is included in the generated documentation.
  166.  You can actually include signature and arg directives
  167.  at any point in this pod -- they are stripped after.
  168.  In fact, any pod is valid in here, until the =cut.
  169.  
  170.  =cut
  171.  void foo (...)
  172.      PPCODE:
  173.         /* crazy code follows */
  174.  
  175. =item =for arg name (type) description
  176.  
  177. =item =for arg name description
  178.  
  179. The arg directive adds or overrides an argument description.  The
  180. description text is optional, as is the type specification (the part
  181. in parentheses).  If you want to hide an argument, specify C<__hide__>
  182. as its type.  The arg name does I<not> need to include a sigil,
  183. as dollar signs will be added.  FIXME what about @ for lists?
  184.  
  185. =back
  186.  
  187. Also, we honor a couple of "modifiers" on the =for apidoc line, following the
  188. symbol name, if present:
  189.  
  190. =over
  191.  
  192. =item - __hide__
  193.  
  194. Do not document this xsub.  This is handy in certain situations, e.g., for
  195. private functions.  DESTROY always has this turned on, for example.
  196.  
  197. =item - __gerror__
  198.  
  199. This function or method can generate a Glib::Error exception.
  200.  
  201. =item - __function__
  202.  
  203. Generate a function-style signature for this xsub.  The default is to
  204. generate method-style signatures.
  205.  
  206. =item - __deprecated__
  207.  
  208. This function or method is deprecated and should not be used in newly written
  209. code.
  210.  
  211. =back
  212.  
  213. (These are actually handled by Glib::ParseXSDoc, but we list them here
  214. because, well, they're an important part of how you document the XS files.)
  215.  
  216. =back
  217.  
  218. =head1 FUNCTIONS
  219.  
  220. =over
  221.  
  222. =cut
  223.  
  224. =item xsdoc2pod ($datafile, $outdir='blib/lib', index=undef)
  225.  
  226. Given a I<$datafile> containing the output of xsdocparse.pl, create in 
  227. I<$outdir> a pod file for each package, containing everything we can think
  228. of for that module.  Output is controlled by the C<=for object> directives
  229. and such in the source code.
  230.  
  231. If you don't want each package to create a separate pod file, then use
  232. this function's code as a starting point for your own pretty-printer.
  233.  
  234. =cut
  235.  
  236. sub xsdoc2pod
  237. {
  238.     my $datafile = shift();
  239.     my $outdir   = shift() || 'blib/lib';
  240.     my $index    = shift;
  241.  
  242.     mkdir $outdir unless (-d $outdir);
  243.  
  244.     die "usage: $0 datafile [outdir]\n"
  245.         unless defined $datafile;
  246.  
  247.     require $datafile;
  248.  
  249.     my @files = ();
  250.  
  251.     my $pkgdata;
  252.     my $ret;
  253.  
  254.     foreach my $package (sort { ($a->isa('Glib::Object') ? -1 : 1) } 
  255.                 keys %$data)
  256.     {
  257.         $pkgdata = $data->{$package};
  258.  
  259.         my $pod = File::Spec->catfile ($outdir, split /::/, $package)
  260.                 . '.pod';
  261.         my (undef, @dirs, undef) = File::Spec->splitpath ($pod);
  262.         mkdir_p (File::Spec->catdir (@dirs));
  263.  
  264.         open POD, ">$pod" or die "can't open $pod for writing: $!\n";
  265.         select POD;
  266.  
  267.         $package = $pkgdata->{object} if (exists $pkgdata->{object});
  268.  
  269.         preprocess_pod ($_) foreach (@{$pkgdata->{pods}});
  270.  
  271.         push @files, {
  272.             name => $package,
  273.             file => $pod,
  274.             blurb => $pkgdata->{blurb},
  275.         };
  276.  
  277.         # podify_pods() always returns proper POD with a =cut at the
  278.         # end.  But all the other =head1 below need a closing =cut.
  279.  
  280.         print "=head1 NAME\n\n$package";
  281.                 if(exists ($pkgdata->{blurb})) {
  282.         print ' - '.$pkgdata->{blurb};
  283.                 } elsif($package =~ m/^Gtk2::Pango/) {
  284.                 my $newname = $package;
  285.                 $newname =~ s/Gtk2:://;
  286.                 print ' - moved to ' . $newname . ', kept for backwards compatibility'
  287.                 } elsif(convert_to_cname($package)) {
  288.                 print ' - wrapper for '.convert_to_cname($package);
  289.                 }
  290.         print "\n\n=cut\n\n";
  291.  
  292.         #                   pods            , position 
  293.         $ret = podify_pods ($pkgdata->{pods}, 'SYNOPSIS');
  294.         print "$ret\n\n" if ($ret);
  295.         
  296.         $ret = podify_pods ($pkgdata->{pods}, 'DESCRIPTION');
  297.         print "$ret\n\n" if ($ret);
  298.         
  299.         my $parents;
  300.         ($ret, $parents) = podify_ancestors ($package);
  301.         print "=head1 HIERARCHY\n\n$ret\n\n=cut\n\n" if ($ret);
  302.         
  303.         $ret = podify_pods ($pkgdata->{pods}, 'post_hierarchy');
  304.         print "$ret\n\n" if ($ret);
  305.         
  306.         $ret = podify_interfaces ($package);
  307.         print "=head1 INTERFACES\n\n$ret\n\n=cut\n\n" if ($ret);
  308.         
  309.         $ret = podify_pods ($pkgdata->{pods}, 'post_interfaces');
  310.         print "$ret\n\n" if ($ret);
  311.  
  312.         $ret = podify_pods ($pkgdata->{pods});
  313.         print "$ret\n\n" if ($ret);
  314.  
  315.         $ret = podify_deprecated_by ($package, @{ $pkgdata->{deprecated_bys} });
  316.         print "\n=head1 DEPRECATION WARNING\n\n$ret\n\n=cut\n\n" if ($ret);
  317.  
  318.         $ret = podify_methods ($package, $pkgdata->{xsubs});
  319.         print "\n=head1 METHODS\n\n$ret\n\n=cut\n\n" if ($ret);
  320.         
  321.         $ret = podify_pods ($pkgdata->{pods}, 'post_methods');
  322.         print "$ret\n\n" if ($ret);
  323.  
  324.         $ret = podify_properties ($package);    
  325.         print "\n=head1 PROPERTIES\n\n$ret\n\n=cut\n\n" if ($ret);
  326.  
  327.         $ret = podify_child_properties ($package);
  328.         print "\n=head1 CHILD PROPERTIES\n\n$ret\n\n=cut\n\n" if ($ret);
  329.  
  330.         $ret = podify_style_properties ($package);
  331.         print "\n=head1 STYLE PROPERTIES\n\n$ret\n\n=cut\n\n" if ($ret);
  332.  
  333.         $ret = podify_pods ($pkgdata->{pods}, 'post_properties');
  334.         print "$ret\n\n" if ($ret);
  335.  
  336.         $ret = podify_signals ($package);    
  337.         print "\n=head1 SIGNALS\n\n$ret\n\n=cut\n\n" if ($ret);
  338.  
  339.         $ret = podify_pods ($pkgdata->{pods}, 'post_signals');
  340.         print "$ret\n\n" if ($ret);
  341.  
  342.         $ret = podify_enums_and_flags ($pkgdata, $package);    
  343.         print "\n=head1 ENUMS AND FLAGS\n\n$ret\n\n=cut\n\n" if ($ret);
  344.  
  345.         $ret = podify_pods ($pkgdata->{pods}, 'post_enums');
  346.         print "$ret\n\n" if ($ret);
  347.  
  348.         $ret = podify_pods ($pkgdata->{pods}, 'SEE_ALSO');
  349.         if ($ret)
  350.         {
  351.             print "$ret\n\n";
  352.         }
  353.         else
  354.         {
  355.             # don't link to yourself
  356.             pop @$parents;
  357.             # link to the toplevel, if we can.
  358.             unshift @$parents, $MAIN_MOD if $MAIN_MOD;
  359.  
  360.             $ret = podify_see_alsos (@$parents,
  361.                                      $pkgdata->{see_alsos}
  362.                          ? @{ $pkgdata->{see_alsos} }
  363.                                      : ());
  364.             print "\n=head1 SEE ALSO\n\n$ret\n\n=cut\n\n" if ($ret);
  365.         }
  366.  
  367.         $ret = podify_pods ($pkgdata->{pods}, 'COPYRIGHT');
  368.         if ($ret)
  369.         {
  370.             # copyright over-ridden
  371.             print "$ret\n\n" 
  372.         }
  373.         else
  374.         {
  375.             # use normal copyright system
  376.             $ret = get_copyright ();
  377.             print "\n=head1 COPYRIGHT\n\n$ret\n\n=cut\n\n" if ($ret);
  378.         }
  379.  
  380.         close POD;
  381.     }
  382.  
  383.     if ($index) {
  384.         open INDEX, ">$index"
  385.             or die "can't open $index for writing: $!\b";
  386.         select INDEX;
  387.  
  388.         foreach (sort {$a->{name} cmp $b->{name}} @files) {
  389.             print join("\t", $_->{file},
  390.                    $_->{name},
  391.                    $_->{blurb} ? $_->{blurb} : () ) . "\n";
  392.         }
  393.         
  394.         close INDEX;
  395.     }
  396. }
  397.  
  398. # more sensible names for the basic types
  399. our %basic_types = (
  400.     # the perl wrappers for the GLib fundamentals
  401.     'Glib::Scalar'  => 'scalar',
  402.     'Glib::String'  => 'string',
  403.     'Glib::Int'     => 'integer',
  404.     'Glib::Uint'    => 'unsigned',
  405.     'Glib::Double'  => 'double',
  406.     'Glib::Float'   => 'float',
  407.     'Glib::Boolean' => 'boolean',
  408.  
  409.     # sometimes we can get names that are already mapped...
  410.     # e.g., from =for arg lines.  pass them unbothered.
  411.     scalar     => 'scalar',
  412.     subroutine => 'subroutine',
  413.     integer    => 'integer',
  414.     string     => 'string',
  415.     package    => 'package',
  416.     list       => 'list',
  417.  
  418.     # other C names which may sneak through
  419.     bool     => 'boolean', # C++ keyword, but provided by the perl api
  420.     boolean  => 'boolean',
  421.     int      => 'integer',
  422.     uint     => 'unsigned',
  423.     float    => 'double',
  424.     double   => 'double',
  425.     char     => 'string',
  426.     unsigned => 'unsigned',
  427.  
  428.     gboolean => 'boolean',
  429.     gint     => 'integer',
  430.     gint8    => 'integer',
  431.     gint16   => 'integer',
  432.     gint32   => 'integer',
  433.     guint8   => 'unsigned',
  434.     guint16  => 'unsigned',
  435.     guint32  => 'unsigned',
  436.     glong    => 'integer',
  437.     gulong   => 'unsigned',
  438.     gshort   => 'integer',
  439.     guint    => 'integer',
  440.     gushort  => 'unsigned',
  441.     gint64   => '64 bit integer',
  442.     guint64  => '64 bit unsigned',
  443.     gfloat   => 'double',
  444.     gdouble  => 'double',
  445.     gsize    => 'unsigned',
  446.     gssize   => 'integer',
  447.     goffset  => '64 bit integer',
  448.     gchar    => 'string',
  449.  
  450.     SV       => 'scalar',
  451.     UV       => 'unsigned',
  452.     IV       => 'integer',
  453.     CV       => 'subroutine',
  454.     AV       => 'arrayref',
  455.  
  456.     gchar_length => 'string',
  457.     gchar_utf8_length => 'string',
  458.  
  459.     FILE => 'file handle',
  460.     time_t => 'unix timestamp',
  461.  
  462.     GPerlFilename    => 'localized file name',
  463.     GPerlFilename_const    => 'localized file name',
  464. );
  465.  
  466. unless (Glib->CHECK_VERSION (2, 4, 0)) {
  467.     $basic_types{'Glib::Strv'} = 'ref to array of strings';
  468. }
  469.  
  470. =item add_types (@filenames)
  471.  
  472. Parse the given I<@filenames> for entries to add to the C<%basic_types> used
  473. for C type name to Perl package name mappings of types that are not registered
  474. with the Glib type system.  The file format is dead simple: blank lines are
  475. ignored; /#.*$/ is stripped from each line as comments; the first token on
  476. each line is considered to be a C type name, and the remaining tokens are the
  477. description of that type.  For example, a valid file may look like this:
  478.  
  479.   # a couple of special types
  480.   FooBar      Foo::Bar
  481.   Frob        localized frobnicator
  482.  
  483. C type decorations such as "const" and "*" are implied (do not include them),
  484. and the _ornull variant is handled for you.
  485.  
  486. =cut
  487.  
  488. sub add_types {
  489.     my @files = @_;
  490.     foreach my $f (@files) {
  491.         open IN, $f or die "can't open types file $f: $!\n";
  492.         my $n = 0;
  493.         while (<IN>) {
  494.             chomp;
  495.             s/#.*//;
  496.             next if m/^\s*$/;
  497.             my ($c_name, @bits) = split;
  498.             if (@bits) {
  499.                 $basic_types{$c_name} = join ' ', @bits;
  500.                 $n++;
  501.             } else {
  502.                 warn "$f:$.: no description for $c_name\n"
  503.             }
  504.         }
  505.         print "Loaded $n extra types from $f\n";
  506.         close IN;
  507.     }
  508. }
  509.  
  510.  
  511. =item $string = podify_properties ($packagename)
  512.  
  513. Pretty-print the object properties owned by the Glib::Object derivative
  514. I<$packagename> and return the text as a string.  Returns undef if there
  515. are no properties or I<$package> is not a Glib::Object.
  516.  
  517. =cut
  518.  
  519. sub podify_properties {
  520.     my $package = shift;
  521.     my @properties;
  522.     eval { @properties = Glib::Object::list_properties($package); 1; }
  523.       || return undef;
  524.     return _podify_pspecs($package, @properties);
  525. }
  526.  
  527. sub _podify_pspecs {
  528.     my ($package, @properties) = @_;
  529.     return undef unless (@properties);
  530.  
  531.     # we have a non-zero number of properties, but there may still be
  532.     # none for this particular class.  keep a count of how many
  533.     # match this class, so we can return undef if there were none.
  534.     my $nmatch = 0;
  535.     my $str = "=over\n\n";
  536.     foreach my $p (sort { $a->{name} cmp $b->{name} } @properties) {
  537.         next unless $p->{owner_type} eq $package;
  538.         ++$nmatch;
  539.         my $stat = join " / ",  @{ $p->{flags} };
  540.         my $type = exists $basic_types{$p->{type}}
  541.               ? $basic_types{$p->{type}}
  542.               : $p->{type};
  543.         my $default = _pspec_formatted_default($p);
  544.         $str .= "=item '$p->{name}' ($type : default $default : $stat)\n\n";
  545.         $str .= "$p->{descr}\n\n" if (exists ($p->{descr}));
  546.     }
  547.     $str .= "=back\n\n";
  548.  
  549.     return $nmatch ? $str : undef;
  550. }
  551.  
  552. # return a POD string which is the default value of $pspec, nicely formatted
  553. sub _pspec_formatted_default {
  554.   my ($pspec) = @_;
  555.   my $default = $pspec->get_default_value;
  556.   if (! defined $default) {
  557.     return 'undef';
  558.   }
  559.   my $pname = $pspec->get_name;
  560.   my $type = $pspec->get_value_type;
  561.  
  562.   # Crib: "eq" here because Glib::Boolean->isa('Glib::Boolean') is false,
  563.   # it's not an actual perl module
  564.   if ($type eq 'Glib::Boolean') {
  565.     $default = ($default ? 'true' : 'false');
  566.  
  567.   } elsif ($type->isa('Glib::Flags')) {
  568.     $default = join ",", @$default;
  569.  
  570.   } elsif ($pspec->isa('Glib::Param::Unichar')) {
  571.     # $default is a single-char string, show as ordinal and string.
  572.     # $type is only Glib::UInt, so this must be before plain UInts below.
  573.     # Eg. Gtk2::Entry property "invisible-char".
  574.     $default = ord($default) . ' ' . Data::Dumper->new([$default])
  575.       ->Useqq(1)->Terse(1)->Indent(0)->Dump;
  576.  
  577.   } elsif ($type eq 'Glib::Double' && $default == POSIX::DBL_MAX()) {
  578.     # Show DBL_MAX symbolically.
  579.     # Eg. Gtk2::Range property "fill-level" is DBL_MAX.
  580.     $default = "DBL_MAX";
  581.   } elsif ($type eq 'Glib::Double' && $default == - POSIX::DBL_MAX()) {
  582.     $default = "-DBL_MAX";
  583.   } elsif ($type eq 'Glib::Float' && $default == POSIX::FLT_MAX()) {
  584.     $default = "FLT_MAX";
  585.   } elsif ($type eq 'Glib::Float' && $default == - POSIX::FLT_MAX()) {
  586.     $default = "-FLT_MAX";
  587.  
  588.   } elsif ($type eq 'Glib::Double' || $type eq 'Glib::Float') {
  589.     # Limit the decimals shown in floats,
  590.     # eg. Gtk2::Menu style property "arrow-scaling" is 0.7 and comes out as
  591.     # 0.6999999999 if not restricted a bit
  592.     $default = sprintf '%.6g', $default;
  593.  
  594.   } elsif ($pname =~ /keyval/
  595.        && $type eq 'Glib::UInt'
  596.        && eval { require Gtk2; 1 }) {
  597.     # Keyvals in hex the same as gdkkeysyms.h, and show the symbol if known.
  598.     # The pspec type of keyvals is only UInt, must guess from the property
  599.     # name whether a uint is in fact a keyval.
  600.     # eg. Gtk2::Label property "mnemonic-keyval" is 0xFFFFFF=VoidSymbol
  601.     my $keyname = Gtk2::Gdk->keyval_name ($default);
  602.     $default = sprintf '0x%02X', $default;  # two or more hex digits
  603.     if (defined $keyname) {
  604.       $default = "$default $keyname";
  605.     }
  606.  
  607.   } elsif ($type eq 'Glib::Int' && $default == POSIX::INT_MAX()) {
  608.     # Show INT_MAX symbolically
  609.     # eg. Gtk2::Paned property "max-position" is INT_MAX
  610.     $default = "INT_MAX";
  611.   } elsif ($type eq 'Glib::Int' && $default == POSIX::INT_MIN()) {
  612.     $default = "INT_MIN";
  613.   } elsif ($type eq 'Glib::UInt' && $default == POSIX::UINT_MAX()) {
  614.     $default = "UINT_MAX";
  615.  
  616.   } else {
  617.     # Strings quoted for clarity, unprintables shown backslashed
  618.     # eg. Gtk2::UIManager property "ui" has newlines
  619.     # eg. Gtk2::TreeView style property "tree-line-pattern" is bytes "\001\001"
  620.     $default = Data::Dumper->new([$default])
  621.       ->Useqq(1)->Terse(1)->Indent(0)->Dump;
  622.   }
  623.  
  624.   # Escape "<" to E<lt> etc.
  625.   # eg. Gtk2::UIManager property "ui" is "<ui></ui>"
  626.   $default = _pod_escape($default);
  627.  
  628.   return $default;
  629. }
  630.  
  631. # Return $str with characters escaped ready to appear in pod.  This means
  632. # non-ascii escaped to E<123> and "<" to E<lt>.  Strictly speaking "<" only
  633. # has to be escaped if it would be B<... etc, but it's easier to do it
  634. # always and might help some of the pod formatters.  $str is assumed to have
  635. # no non-printables (control chars etc).
  636. # (ENHANCE-ME: Is there a module to do char->pod like this?  Pod::Escapes is
  637. # the converse pod->char ...)
  638. sub _pod_escape {
  639.   my ($str) = @_;
  640.   $str =~ s{([^[:ascii:]])|(<)}
  641.        {defined $1 ? ('E<'.ord($1).'>') : 'E<lt>'}eg;
  642.   return $str;
  643. }
  644.  
  645. =item $string = podify_child_properties ($packagename)
  646.  
  647. Pretty-print the child properties owned by the Gtk2::Container derivative
  648. I<$packagename> and return the text as a string.  Returns undef if there are
  649. no child properties or I<$package> is not a Gtk2::Container or similar class
  650. with a C<list_child_properties()> method.
  651.  
  652. =cut
  653.  
  654. sub podify_child_properties {
  655.     my ($package) = shift;
  656.     # Call list_child_properties() as a method so as to perhaps work on
  657.     # Goo::Canvas::Item which has a similar child properties scheme of
  658.     # its own (it's not a Gtk2::Container subclass), though that method
  659.     # is not wrapped as of Goo::Canvas 0.06.
  660.     if ($package->can('list_child_properties')) {
  661.       return _podify_pspecs($package, $package->list_child_properties);
  662.     } else {
  663.       return undef;
  664.     }
  665. }
  666.  
  667. =item $string = podify_style_properties ($packagename)
  668.  
  669. Pretty-print the style properties owned by the Gtk2::Widget derivative
  670. I<$packagename> and return the text as a string.  Returns undef if there are
  671. no style properties or I<$package> is not a Gtk2::Widget or similar class
  672. with a C<list_style_properties()> method.
  673.  
  674. =cut
  675.  
  676. sub podify_style_properties {
  677.     my ($package) = shift;
  678.     my @properties;
  679.     if ($package->can('list_style_properties')) {
  680.       return _podify_pspecs($package, $package->list_style_properties);
  681.     } else {
  682.       return undef;
  683.     }
  684. }
  685.  
  686. =item $string = podify_values ($packagename)
  687.  
  688. List and pretty-print the values of the GEnum or GFlags type I<$packagename>,
  689. and return the text as a string.  Returns undef if I<$packagename> isn't an
  690. enum or flags type.
  691.  
  692. =cut
  693.  
  694. sub podify_values {
  695.     my $package = shift;
  696.     my @values;
  697.     eval { @values = Glib::Type->list_values ($package); 1; };
  698.     return undef unless (@values or not $@);
  699.  
  700.     return "=over\n\n"
  701.          . join ("\n\n", map { "=item * '$_->{nick}' / '$_->{name}'" } @values)
  702.          . "\n\n=back\n\n";
  703. }
  704.  
  705. =item $string = podify_signals ($packagename)
  706.  
  707. Query, list, and pretty-print the signals associated with I<$packagename>.
  708. Returns the text as a string, or undef if there are no signals or
  709. I<$packagename> is not a Glib::Object derivative.
  710.  
  711. =cut
  712.  
  713. sub podify_signals {
  714.     my $str = undef;
  715.     eval {
  716.     my @sigs = Glib::Type->list_signals (shift);
  717.     return undef unless @sigs;
  718.     $str = "=over\n\n";
  719.     foreach (@sigs) {
  720.         $str .= '=item ';
  721.         $str .= convert_type ($_->{return_type}).' = '
  722.             if exists $_->{return_type};
  723.         $str .= "B<$_->{signal_name}> (";
  724.         $str .= join ', ', map { convert_type ($_) }
  725.                 $_->{itype}, @{$_->{param_types}};
  726.         $str .= ")\n\n";
  727.     }
  728.     $str .= "=back\n\n";
  729.     };
  730.     return $str
  731. }
  732.  
  733. =item $string = podify_deprecated_by ($packagename, @deprecated_by)
  734.  
  735. Creates a deprecation warning for $packagename, suggesting using the items
  736. inside @deprecated_by instead.
  737.  
  738. =cut
  739.  
  740. sub podify_deprecated_by
  741. {
  742.     my $package       = shift;
  743.     my @deprecated_by = @_;
  744.  
  745.     return undef unless scalar @deprecated_by;
  746.  
  747.     my $str = "$package has been marked as deprecated, and should not be "
  748.             . "used in newly written code.\n\n";
  749.  
  750.     # create the deprecated for list
  751.     $str .= "You should use "
  752.           . join (', ',
  753.                   map {
  754.             if (/^\s*L</) {
  755.                 $_;
  756.             }
  757.             else {
  758.                 "L<$_>";
  759.             }
  760.               } @deprecated_by)
  761.           . " instead of $package.\n";
  762.  
  763.     return $str;
  764. }
  765.  
  766. sub podify_enums_and_flags
  767. {
  768.     my $pkgdata = shift;
  769.     my $package = shift;
  770.     
  771.     my %types = ();
  772.     
  773.     my $name;
  774.     my $pod;
  775.     my %info = ();
  776.     foreach (@{$pkgdata->{enums}})
  777.     {
  778.         $name = convert_type ($_->{name});
  779.             
  780.         $pod = $_->{pod};
  781.         shift @{ $pod->{lines} };
  782.         pop @{ $pod->{lines} } if $pod->{lines}[-1] =~ /^=cut/;
  783.  
  784.         $info{$name} = {
  785.             type => $_->{type},
  786.             pod  => $pod->{lines},
  787.         };
  788.         $types{$name}++;
  789.     }
  790.  
  791.     foreach my $xsub (@{$pkgdata->{xsubs}})
  792.     {
  793.         if ($xsub->{return_type})
  794.         {
  795.             foreach my $ret (@{$xsub->{return_type}})
  796.             {
  797.                 $name = convert_type ($ret);
  798.                 $types{$name}++;
  799.             }
  800.         }
  801.         if ($xsub->{args})
  802.         {
  803.             foreach my $arg (@{$xsub->{args}})
  804.             {
  805.                 if ($arg->{type})
  806.                 {
  807.                     $name = convert_type ($arg->{type});
  808.                     $types{$name}++;
  809.                 }
  810.             }
  811.         }
  812.     }
  813.  
  814.     if ($package)
  815.     {
  816.         my @props;
  817.         eval { @props = Glib::Object::list_properties($package); 1; };
  818.         foreach my $prop (@props)
  819.         {
  820.             next unless ($prop->{type});
  821.             next unless $prop->{owner_type} eq $package;
  822.             $name = convert_type ($prop->{type});
  823.             $types{$name}++;
  824.         }
  825.         
  826.         my @sigs;
  827.         eval { @sigs = Glib::Type->list_signals ($package); 1; };
  828.         foreach my $sig (@sigs)
  829.         {
  830.             if ($sig->{return_type})
  831.             {
  832.                 $name = convert_type ($sig->{return_type});
  833.                 $types{$name}++;
  834.             }
  835.             foreach (@{$sig->{param_types}})
  836.             {
  837.                 next unless ($_);
  838.                 $name = convert_type ($_);
  839.                 $types{$name}++;
  840.             }
  841.         }
  842.     }
  843.  
  844.     my $ret = '';
  845.     foreach (sort keys %types)
  846.     {
  847.         s/\s.*//;
  848.  
  849.         next if $_ eq 'Glib::Enum' || $_ eq 'Glib::Flags';
  850.  
  851.         my $values_pod = podify_values ($_);
  852.  
  853.         if ($values_pod || exists $info{$_})
  854.         {
  855.             my $type = UNIVERSAL::isa ($_, 'Glib::Flags') ?
  856.                     'flags' : 'enum';
  857.             $ret .= "=head2 $type $_\n\n";
  858.             $ret .= join ("\n", @{$info{$_}{pod}}) . "\n\n"
  859.                 if ($info{$_}{pod});
  860.             $ret .= podify_values ($_) . "\n";
  861.         }
  862.     }
  863.     
  864.     return $ret;
  865. }
  866.  
  867.  
  868. =item $string = podify_pods ($pods, $position)
  869.  
  870. Helper function to allow specific placement of generic pod within the auto
  871. generated pages. Pod sections starting out with =for position XXX, where XXX
  872. is one of the following will be placed at a specified position. In the case of
  873. pod that is to be placed after a particular section that doesn't exist, that
  874. pod will be still be placed there.
  875.  
  876. This function is called at all of the specified points through out the process
  877. of generating pod for a page. Any pod matching the I<position> passed will be
  878. returned, undef if no matches were found.  If I<position> is undef all pods
  879. without sepcific postion information will be returned. I<pods> is a reference
  880. to an array of pod hashes.
  881.  
  882. =over
  883.  
  884. =item * SYNOPSIS
  885.  
  886. After the NAME section
  887.  
  888. =item * DESCRIPTION
  889.  
  890. After the SYNOPSIS section.
  891.  
  892. =item * post_hierarchy
  893.  
  894. After the HIERARCHY section.
  895.  
  896. =item * post_interfaces
  897.  
  898. After the INTERFACE section.
  899.  
  900. =item * post_methods
  901.  
  902. After the METHODS section.
  903.  
  904. =item * post_properties
  905.  
  906. After the PROPERTIES section.
  907.  
  908. =item * post_signals
  909.  
  910. After the SIGNALS section.
  911.  
  912. =item * post_enums
  913.  
  914. After the ENUMS AND FLAGS section.
  915.  
  916. =item * SEE_ALSO
  917.  
  918. Replacing the autogenerated SEE ALSO section completely.
  919.  
  920. =item * COPYRIGHT
  921.  
  922. Replacing the autogenerated COPYRIGHT section completely.
  923.  
  924. =back
  925.  
  926. =cut
  927.  
  928. sub podify_pods
  929. {
  930.     my $pods = shift;
  931.     my $position = shift;
  932.  
  933.     my $ret = '';
  934.  
  935.     if ($position)
  936.     {
  937.         foreach (@$pods)
  938.         {
  939.             $ret .= join ("\n", @{$_->{lines}})."\n\n"
  940.                 if (exists ($_->{position}) and 
  941.                     $_->{position} eq $position);
  942.         }
  943.     }
  944.     else
  945.     {
  946.         foreach (@$pods)
  947.         {
  948.             $ret .= join ("\n", @{$_->{lines}})."\n\n"
  949.                 unless ($_->{position});
  950.         }
  951.     }
  952.     return $ret ne '' ? $ret : undef;
  953. }
  954.  
  955. =item $string = podify_ancestors ($packagename)
  956.  
  957. Pretty-prints the ancestry of I<$packagename> from the Glib type system's
  958. point of view.  This uses Glib::Type->list_ancestors; see that function's
  959. docs for an explanation of why that's different from looking at @ISA.
  960.  
  961. Returns the new text as a string, or undef if I<$packagename> is not a
  962. registered GType.
  963.  
  964. =cut
  965.  
  966. sub podify_ancestors {
  967.     my @anc;
  968.     eval { @anc = Glib::Type->list_ancestors (shift); 1; };
  969.     return undef unless (@anc or not $@);
  970.  
  971.     my $parents = [ reverse @anc ];
  972.  
  973.     my $depth = 0;
  974.     my $str = '  '.pop(@anc)."\n";
  975.     foreach (reverse @anc) {
  976.         $str .= "  " . "     "x$depth . "+----$_\n";
  977.         $depth++;
  978.     }
  979.     $str .= "\n";
  980.  
  981.     return ($str, $parents);
  982. }
  983.  
  984. =item $string = podify_interfaces ($packagename)
  985.  
  986. Pretty-print the list of GInterfaces that I<$packagename> implements.
  987. Returns the text as a string, or undef if the type implements no interfaces.
  988.  
  989. =cut
  990.  
  991. sub podify_interfaces {
  992.     my @int;
  993.     eval { @int = Glib::Type->list_interfaces (shift); 1; };
  994.     return undef unless (@int or not defined ($@));
  995.     return '  '.join ("\n  ", @int)."\n\n";
  996. }
  997.  
  998. =item $string = podify_methods ($packagename)
  999.  
  1000. Call C<xsub_to_pod> on all the xsubs under the key I<$packagename> in the
  1001. data extracted by xsdocparse.pl.
  1002.  
  1003. Returns the new text as a string, or undef if there are no xsubs in
  1004. I<$packagename>.
  1005.  
  1006. =cut
  1007.  
  1008. sub podify_methods
  1009. {
  1010.     my $package = shift;
  1011.     my $xsubs = shift;
  1012.     return undef unless $xsubs && @$xsubs;
  1013.     # we will be re-using $package from here on out.
  1014.  
  1015.     my $str = '';
  1016.     my $nfound = 0;
  1017.     my $nused  = 0;
  1018.     my $method;
  1019.  
  1020.     # based on rm's initial thought and then code/ideas by Marc 'HE'
  1021.     # Brockschmidt, and Peter Haworth
  1022.     @$xsubs = sort { 
  1023.         my ($at, $bt);
  1024.         for ($at=$a->{symname}, $bt=$b->{symname})
  1025.         {
  1026.             # remove prefixes
  1027.             s/^.+:://;
  1028.             # new's goto the front
  1029.             s/^new/\x00/;
  1030.             # group set's/get'ss
  1031.             s/^(get|set)_(.+)/$2_$1/;
  1032.             # put \<set\>'s with \<get\>'s
  1033.             s/^(get|set)$/get_$1/;
  1034.         }
  1035.         # now actually do the sorting compare
  1036.         $at cmp $bt; 
  1037.     } @$xsubs;
  1038.  
  1039.     #$str .= "=over\n\n";
  1040.     foreach (@$xsubs) {
  1041.         # skip if the method is hidden
  1042.         next if ($_->{hidden});
  1043.         
  1044.         $_->{symname} =~ m/^(?:([\w:]+)::)?([\w]+)$/;
  1045.         $package = $1 || $_->{package};
  1046.         $method = $2;
  1047.  
  1048.         # skip DESTROY altogether
  1049.         next if $method eq 'DESTROY';
  1050.  
  1051.         ++$nfound;
  1052.  
  1053.         # don't document it if we can't actually call it.
  1054.         if ($package->can ($method)) {
  1055.             $str .= xsub_to_pod ($_, '=head2');
  1056.             ++$nused;
  1057.         } else {
  1058.             # this print should only be temporary
  1059.             print STDERR "missing: $package->$method\n";
  1060.         }
  1061.     }
  1062.     #$str .= "=back\n\n";
  1063.  
  1064.     if ($nused == 0) {
  1065.         # no xsubs were used.
  1066.         if ($nfound > 0) {
  1067.             # but some were found and not used.  
  1068.             # say something to that effect.
  1069.             print STDERR "No methods found for $package\n";
  1070.             $str = "
  1071.  
  1072. Some methods defined for $package are not available in the particular
  1073. library versions against which this module was compiled. 
  1074.  
  1075. ";
  1076.         } else {
  1077.             # no methods found, nothing to say
  1078.             $str = undef;
  1079.         }
  1080.     }
  1081.             
  1082.     $str;
  1083. }
  1084.  
  1085. =item $string = podify_see_alsos (@entries)
  1086.  
  1087. Creates a list of links to be placed in the SEE ALSO section of the page.
  1088. Returns undef if nothing is in the input list.
  1089.  
  1090. =cut
  1091.  
  1092. sub podify_see_alsos
  1093. {
  1094.     my @entries = @_;
  1095.  
  1096.     return undef unless scalar @entries;
  1097.     
  1098.     # create the see also list
  1099.     join (', ',
  1100.         map {
  1101.             if (/^\s*L</) {
  1102.                 $_;
  1103.             } else {
  1104.                 "L<$_>";
  1105.             }
  1106.         }
  1107.         @entries)
  1108.         . "\n";
  1109. }
  1110.  
  1111. =item $string = get_copyright
  1112.  
  1113. Returns a string that will/should be placed on each page.  You can control
  1114. the text of this string by calling the class method I<set_copyright>.
  1115.  
  1116. If no text has been set, we will attempt to create one for you, using what
  1117. has been passed to I<set_year>, I<set_authors>, and I<set_main_mod>.  The
  1118. year defaults to the current year, the authors default to
  1119. 'The Gtk2-Perl Team', and the main mod is empty by default.  You want the
  1120. main mod to be set to the main module of your extension for the SEE ALSO
  1121. section, and on the assumption that a decent license notice can be found in
  1122. that module's doc, we point the reader there.
  1123.  
  1124. So, in general, you will want to specify at least one of these, so that you
  1125. don't credit your work to us under the LGPL.
  1126.  
  1127. To set them do something similar to the following in the first part of your
  1128. postamble section in Makefile.PL.  All occurences of <br> in the copyright
  1129. are replaced with newlines, to make it easier to put in a multi-line string.
  1130.  
  1131.   POD_SET=Glib::GenPod::set_copyright(qq{Copyright 1999 team-foobar<br>LGPL});
  1132.  
  1133. Glib::MakeHelper::postamble_docs_full() does this sort of thing for you.
  1134.  
  1135. =cut
  1136.  
  1137. sub get_copyright
  1138. {
  1139.     my $str = $COPYRIGHT;
  1140.     if (! $str) {
  1141.         # construct a default.
  1142.         $str = "\nCopyright (C) $YEAR $AUTHORS\n\n";
  1143.         $str .= "This software is licensed under the LGPL;"
  1144.              . " see $MAIN_MOD for a full notice.\n"
  1145.             if $MAIN_MOD;
  1146.     }
  1147.  
  1148.     # a way to make returns    
  1149.     $str =~ s/<br>/\n/g;
  1150.     return $str."\n";
  1151. }
  1152.  
  1153. sub set_copyright {
  1154.     $COPYRIGHT = shift;
  1155. }
  1156.  
  1157. sub set_year {
  1158.     $YEAR = shift;
  1159. }
  1160.  
  1161. sub set_authors {
  1162.     $AUTHORS = shift;
  1163. }
  1164.  
  1165. sub set_main_mod {
  1166.     $MAIN_MOD = shift;
  1167.         eval "use $MAIN_MOD";
  1168.         die($@) if($@);
  1169. }
  1170.  
  1171. sub preprocess_pod
  1172. {
  1173.     my $pod = shift;
  1174.  
  1175.     foreach (@{$pod->{lines}})
  1176.     {
  1177.         # =for include filename
  1178.         # =for include !cmd
  1179.         if (/^=for\s+include\s+(!)?(.*)$/)
  1180.         {
  1181.             if ($1)
  1182.             {
  1183.                 chomp($_ = `$2`);
  1184.             }
  1185.             else
  1186.             {
  1187.                 if (open INC, "<$2")
  1188.                 {
  1189.                     local $/ = undef;
  1190.                     $_ = <INC>;
  1191.                 }
  1192.                 else
  1193.                 {
  1194.                     carp "\n\nunable to open $2 for inclusion, at ".
  1195.                          $pod->{filename}.':'.$pod->{line};
  1196.                 }
  1197.             }
  1198.         }
  1199.     }
  1200. }
  1201.  
  1202. =back
  1203.  
  1204. =head2 Helpers
  1205.  
  1206. =over
  1207.  
  1208. =item $perl_type = convert_type ($ctypestring)
  1209.  
  1210. Convert a C type name to a Perl type name.
  1211.  
  1212. Uses %Glib::GenPod::basic_types to look for some known basic types,
  1213. and uses Glib::Type->package_from_cname to look up the registered
  1214. package corresponding to a C type name.  If no suitable mapping can
  1215. be found, this just returns the input string.
  1216.  
  1217. =cut
  1218.  
  1219. sub convert_type {
  1220.     my $typestr = shift;
  1221.  
  1222.     $typestr =~ /^\s*                # leading space
  1223.                   (?:const\s+)?            # maybe a const
  1224.                   ([:\w]+)                # the name
  1225.                   (\s*\*)?                # maybe a star
  1226.                   \s*$/x;                # trailing space
  1227.     my $ctype   = $1 || '!!';
  1228.     if ($ctype eq '!!') {
  1229.         warn "Glib::GenPod: Unable to parse type `$typestr┬┤";
  1230.     }
  1231.  
  1232.     # variant type
  1233.     $ctype =~ s/(?:_(ornull|copy|own_ornull|own|noinc_ornull|noinc))$//;
  1234.     my $variant = $1 || "";
  1235.  
  1236.     my $perl_type;
  1237.  
  1238.     if (exists $basic_types{$ctype}) {
  1239.         $perl_type = $basic_types{$ctype};
  1240.  
  1241.     } elsif ($ctype =~ m/::/) {
  1242.         # :: is not valid in GLib type names, so there's no point
  1243.         # in asking the GLib type system if it knows this name,
  1244.         # because it's probably already a perl type name.
  1245.         $perl_type = $ctype;
  1246.  
  1247.     } else {
  1248.         eval
  1249.         {
  1250.             $perl_type = Glib::Type->package_from_cname ($ctype);
  1251.             1;
  1252.         } or do {
  1253.             # this warning will have something to do with the
  1254.             # package not being registered, a fact which will
  1255.             # of interest to a person documenting or developing
  1256.             # the documented module, but not to us developing
  1257.             # the documentation generator.  thus, this warning
  1258.             # doesn't need a line number attribution.
  1259.             # let's strip that...
  1260.             $@ =~ s/\s*at (.*) line \d+\.$/./;
  1261.             warn "$@";
  1262.             # ... and fall back gracefully.
  1263.             $perl_type = $ctype;
  1264.         }
  1265.     }
  1266.  
  1267.     if ($variant && $variant =~ m/ornull/) {
  1268.         $perl_type .= " or undef";
  1269.     }
  1270.  
  1271.     $perl_type
  1272. }
  1273.  
  1274.  
  1275. =item $string = xsub_to_pod ($xsub, $sigprefix='')
  1276.  
  1277. Convert an xsub hash into a string of pod describing it.  Includes the
  1278. call signature, argument listing, and description, honoring special
  1279. switches in the description pod (arg and signature overrides).
  1280.  
  1281. =cut
  1282.  
  1283. sub xsub_to_pod {
  1284.     my $xsub = shift;
  1285.     my $sigprefix = shift || '';
  1286.     my $alias = $xsub->{symname};
  1287.     my $str;
  1288.  
  1289.     # ensure that if there's pod for this xsub, we have it now.
  1290.     # this should probably happen somewhere outside of this function,
  1291.     # but, eh...
  1292.     my @podlines = ();
  1293.     if (defined $xsub->{pod}) {
  1294.         @podlines = @{ $xsub->{pod}{lines} };
  1295.     }
  1296.  
  1297.     # look for annotations in the pod lines.
  1298.     # stuff in the pods overrides whatever we'd generate.
  1299.     my @signatures = ();
  1300.     if (@podlines) {
  1301.         # since we're modifying the list while traversing
  1302.         # it, go back to front.
  1303.         for (my $i = $#podlines ; $i >= 0 ; $i--) {
  1304.             if ($podlines[$i] =~ s/^=(for\s+)?signature\s+//) {
  1305.                 unshift @signatures, $podlines[$i];
  1306.                 splice @podlines, $i, 1;
  1307.             } elsif ($podlines[$i] =~ /^=(?:for\s+)?arg\s+
  1308.                                        (\$?[\w.]+)   # arg name
  1309.                                        (?:\s*\(([^)]*)\))? # type
  1310.                                        \s*
  1311.                                        (.*)$/x) { # desc
  1312.                 # this is a little convoluted, because we
  1313.                 # need to ensure that the args array and
  1314.                 # hash exist before using them.  we may be
  1315.                 # getting an =arg command on something that
  1316.                 # doesn't list this name in the xsub
  1317.                 # declaration.
  1318.                 $xsub->{args} = [] if not exists $xsub->{args};
  1319.                 my ($a, undef) =
  1320.                     grep { $_->{name} eq $1 }
  1321.                                   @{ $xsub->{args} };
  1322.                 $a = {}, push @{$xsub->{args}}, $a
  1323.                     if not defined $a;
  1324.                 $a->{name} = $1 if not defined $a->{name};
  1325.                 $a->{desc} = $3;
  1326.                 if ($2) {
  1327.                     if ($2 =~ m/^_*hide_*$/i) {
  1328.                         $a->{hide}++;
  1329.                     } else {
  1330.                         $a->{type} = $2;
  1331.                     }
  1332.                 }
  1333.                 # "just eat it!  eat it!  get yourself and
  1334.                 # egg and beat it!"  -- weird al
  1335.                 splice @podlines, $i, 1;
  1336.             }
  1337.         }
  1338.     }
  1339.  
  1340.     #
  1341.     # the call signature(s).
  1342.     #
  1343.     push @signatures, compile_signature ($xsub)
  1344.         unless @signatures;
  1345.  
  1346.     foreach (@signatures) {
  1347.         s/>(\w+)/>B<$1>/;
  1348.         $str .= "$sigprefix $_\n\n";
  1349.     }
  1350.  
  1351.     #
  1352.     # list all the arg types.
  1353.     #
  1354.     my @args;
  1355.     @args = @{ $xsub->{args} } if ($xsub->{args});
  1356.     shift @args unless $xsub->{function};
  1357.  
  1358.     $str .= "=over\n\n" if @args;
  1359.     foreach my $a (@args) {
  1360.         my $type;
  1361.         next if $a->{hide};
  1362.         if ($a->{name} eq '...') {
  1363.             $type = 'list';
  1364.         } else {
  1365.             if (not defined $a->{type}) {
  1366.                 warn "$alias: no type defined for arg"
  1367.                    . " \$$a->{name}\n";
  1368.                 $type = "(unknown)";
  1369.             } else {
  1370.                 $type = convert_arg_type ($a->{type});
  1371.             }
  1372.         }
  1373.         $str .= "=item * "
  1374.               . fixup_arg_name ($a->{name})
  1375.               . " ($type) "
  1376.               . ($a->{desc} ? $a->{desc} : "")
  1377.               . "\n\n";
  1378.     }
  1379.     $str .= "=back\n\n" if @args;
  1380.  
  1381.     if (@podlines) {
  1382.         shift @podlines;
  1383.         pop @podlines;
  1384.         $str .= join("\n", @podlines)."\n\n";
  1385.     }
  1386.  
  1387.     $str .= "May croak with a L<Glib::Error> in \$@ on failure.\n\n"
  1388.         if ($xsub->{gerror});
  1389.  
  1390.     $str .= "This method is deprecated and should not be used in newly written code.\n\n"
  1391.         if ($xsub->{deprecated});
  1392.  
  1393.  
  1394.     # When there are multiple version guards of the same type, we only want
  1395.     # the innermost.
  1396.     my %version_conditions;
  1397.     my %prefix_to_name = (
  1398.         GTK => 'gtk+',
  1399.     );
  1400.     foreach (@{ $xsub->{preprocessor_conditionals} }) {
  1401.         if (m/^\s*(\w+)_CHECK_VERSION\s*\((\d+),\s*(\d+)/) {
  1402.             my $lib_name = $prefix_to_name{$1} || lc $1;
  1403.             $version_conditions{$lib_name} = "$2.$3";
  1404.         }
  1405.     }
  1406.     foreach my $lib_name (keys %version_conditions) {
  1407.         $str .= "Since: $lib_name $version_conditions{$lib_name}\n\n";
  1408.     }
  1409.  
  1410.     $str
  1411. }
  1412.  
  1413. =item $string = compile_signature ($xsub)
  1414.  
  1415. Given an xsub hash, return a string with the call signature for that
  1416. xsub.
  1417.  
  1418. =cut
  1419.  
  1420. sub compile_signature {
  1421.     my $xsub = shift;
  1422.  
  1423.     my @args;
  1424.     @args = @{ $xsub->{args} } if ($xsub->{args});
  1425.  
  1426.     my $call;
  1427.  
  1428.     if ($xsub->{function}) {
  1429.         $call = $xsub->{symname};
  1430.     } else {
  1431.         # find the method's short name
  1432.         my $method = $xsub->{symname};
  1433.         $method =~ s/^(.*):://;
  1434.  
  1435.         my $package = $1 || $xsub->{package};
  1436.  
  1437.         # methods always eat the first arg as the instance.
  1438.         my $instance = shift @args;
  1439.  
  1440.         my $obj = defined ($instance->{type})
  1441.                 ? '$'.$instance->{name}
  1442.             : $package;
  1443.  
  1444.         $call = "$obj\-E<gt>$method";
  1445.     }
  1446.  
  1447.     # compile the arg list string
  1448.     my $argstr = join ", ", map {
  1449.             fixup_arg_name ($_->{name})
  1450.             . (defined $_->{default}
  1451.                ? '='.fixup_default ($_->{default})
  1452.                : '')
  1453.         } @args;
  1454.  
  1455.     # compile the return list string
  1456.     my @outlist = map { $_->{name} } @{ $xsub->{outlist} };
  1457.     if (defined $xsub->{return_type}) {
  1458.         my @retnames = map { convert_return_type_to_name ($_) }
  1459.                 @{ $xsub->{return_type} };
  1460.         unshift @outlist, @retnames;
  1461.     }
  1462.     my $retstr = @outlist
  1463.                ? (@outlist > 1
  1464.               ? "(".join (", ", @outlist).")"
  1465.               : $outlist[0]
  1466.              )." = "
  1467.            : (defined $xsub->{codetype} and
  1468.               $xsub->{codetype} eq 'PPCODE'
  1469.               ? 'list = '
  1470.               : ''
  1471.              );
  1472.     
  1473.     "$retstr$call ".($argstr ? "($argstr)" : "");
  1474. }
  1475.  
  1476. =item $string = fixup_arg_name ($name)
  1477.  
  1478. Prepend a $ to anything that's not the literal ellipsis string '...'.
  1479.  
  1480. =cut
  1481.  
  1482. sub fixup_arg_name {
  1483.     my $name = shift;
  1484.     my $sigil = $name eq '...' ? '' : '$';
  1485.     return $sigil.$name;
  1486. }
  1487.  
  1488. =item fixup_default
  1489.  
  1490. Mangle default parameter values from C to Perl values.  Mostly, this
  1491. does NULL => undef.
  1492.  
  1493. =cut
  1494.  
  1495. sub fixup_default {
  1496.     my $value = shift;
  1497.     return (defined ($value) 
  1498.             ? ($value eq 'NULL' ? 'undef' : $value)
  1499.         : '');
  1500. }
  1501.  
  1502. =item convert_arg_type
  1503.  
  1504. C type to Perl type conversion for argument types.
  1505.  
  1506. =cut
  1507.  
  1508. sub convert_arg_type { convert_type (@_) }
  1509.  
  1510.  
  1511. =item convert_return_type_to_name
  1512.  
  1513. C type to Perl type conversion suitable for return types.
  1514.  
  1515. =cut
  1516.  
  1517. sub convert_return_type_to_name {
  1518.     my $type = convert_type (@_);
  1519.     if ($type =~ s/^.*:://) {
  1520.         $type = lc $type;
  1521.     }
  1522.     return $type;
  1523. }
  1524.  
  1525. sub mkdir_p {
  1526.     my $path = shift;
  1527.     my @dirs = File::Spec->splitdir ($path);
  1528.     my $p = shift @dirs;
  1529.     do {
  1530.         mkdir $p or die "can't create dir $p: $!\n" unless -d $p;
  1531.         $p = File::Spec->catdir ($p, shift @dirs);
  1532.     } while (@dirs);
  1533. }
  1534.  
  1535. sub convert_to_cname {
  1536.     my $perlname = shift;
  1537.     my $cname = $perlname;
  1538.     if($perlname =~ /^Gtk2::Gdk::/) {
  1539.         $cname =~ s/^Gtk2::Gdk::/Gdk/;
  1540.     } elsif($perlname =~ m/^Gtk2::/) {
  1541.         $cname =~ s/^Gtk2::/Gtk/;
  1542.     } elsif($perlname =~ m/^Gnome2::Bonobo::/) {
  1543.         $cname =~ s/^Gnome2::Bonobo::/Bonobo/;
  1544.     } elsif($perlname =~ m/^Gnome2::/) {
  1545.         $cname =~ s/^Gnome2::/Gnome/;
  1546.     }
  1547.     $cname =~ s/:://g;
  1548.     my $tmp;
  1549.     eval { $tmp = Glib::Type->package_from_cname($cname); };
  1550.     if($@ || $tmp ne $perlname) {
  1551.         return;
  1552.     }
  1553.     return $cname;
  1554. }
  1555.  
  1556. 1;
  1557. __END__
  1558.  
  1559. =back
  1560.  
  1561. =head1 SEE ALSO
  1562.  
  1563. L<Glib::ParseXSDoc>
  1564.  
  1565. =head1 AUTHORS
  1566.  
  1567. muppet bashed out the xsub signature generation in a few hours on a wednesday
  1568. night when band practice was cancelled at the last minute; he and ross
  1569. mcfarland hacked this module together via irc and email over the next few days.
  1570.  
  1571. =head1 COPYRIGHT AND LICENSE
  1572.  
  1573. Copyright (C) 2003-2004, 2010, 2011 by the gtk2-perl team
  1574.  
  1575. This library is free software; you can redistribute it and/or modify
  1576. it under the terms of the Lesser General Public License (LGPL).  For 
  1577. more information, see http://www.fsf.org/licenses/lgpl.txt
  1578.  
  1579. =cut
  1580.